#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdbool.h>

#define WIDTH 60
#define HEIGHT 20
#define INIT_LENGTH 5


int snakeX[100], snakeY[100]; 
int snakeLength;              
int foodX, foodY;             
int direction;                
int score;                    
int highScore;                
int speed = 200;              
bool gameOver;                


void printSnake();
void welcomeToGame();
void createMap();
void scoreAndTips();
void fileOut();
void fileIn();
void initSnake();
void createFood();
int biteSelf();
void cantCrossWall();
void speedUp();
void speedDown();
void snakeMove();
void keyboardControl();
void gameOverScreen();
void explanation();


int main() {
    system("mode con cols=80 lines=30"); 
    srand(time(NULL));                   
    fileIn();                            
    welcomeToGame();                     
    return 0;
}


void printSnake() {
    system("cls");
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, 10); // ÂÌÉ«

    printf("\n\n");
    printf("       _____               _                      \n");
    printf("      / ____| _____       | |                     \n");
    printf("     | (___  |  _  | __ _ | | __ ___   \n");
    printf("      \\___ \| | | |\  / _` || |/ // _ \n");
    printf("      ____) || | | | (_| ||   <|  __/   \n");
    printf("     |_____/ |_| |_|\\__,_||_|\\_\\\\___|   \n");
    printf("\n\n");
}


void welcomeToGame() {
    printSnake();

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 15); 
    printf("\n       欢迎来到贪吃蛇游戏!\n\n");
    printf("       1. 开始游戏\n");
    printf("       2. 游戏说明\n");
    printf("       3. 查看最高分\n");
    printf("       4. 退出游戏\n\n");
    printf("       请选择(1-4): ");

    char choice = _getch();
    switch (choice) {
    case '1':
        system("cls");
        createMap();
        initSnake();
        createFood();
        score = 0;
        gameOver = false;
        direction = 2; 
        snakeMove();
        break;
    case '2':
        explanation();
        break;
    case '3':
        system("cls");
        printf("\n\n       当前最高分: %d\n\n", highScore);
        printf("       按任意键返回...");
        _getch();
        welcomeToGame();
        break;
    case '4':
        exit(0);
    default:
        printf("\n       无效输入，请重新选择!");
        Sleep(1000);
        welcomeToGame();
    }
}


void createMap() {
    system("cls");
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hConsole, 11); 

    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            if (i == 0 || i == HEIGHT - 1 || j == 0 || j == WIDTH - 1) {
                printf("#");
            }
            else {
                printf(" ");
            }
        }
        printf("\n");
    }
}


void scoreAndTips() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos = { 0, HEIGHT + 1 };
    SetConsoleCursorPosition(hConsole, pos);
    SetConsoleTextAttribute(hConsole, 15); 

    printf("当前得分: %d  最高分: %d", score, highScore);
    printf("\n操作说明: 方向键控制移动, F1加速, F2减速, ESC退出");
}


void fileIn() {
    FILE* file = fopen("save.txt", "r");
    if (file == NULL) {
        highScore = 0;
    }
    else {
        fscanf(file, "%d", &highScore);
        fclose(file);
    }
}


void fileOut() {
    FILE* file = fopen("save.txt", "w");
    if (file != NULL) {
        fprintf(file, "%d", highScore);
        fclose(file);
    }
}


void initSnake() {
    snakeLength = INIT_LENGTH;
    for (int i = 0; i < snakeLength; i++) {
        snakeX[i] = 24 - i * 2;
        snakeY[i] = 5;
    }
}


void createFood() {
    bool valid;
    do {
        valid = true;
        foodX = rand() % (WIDTH - 2) + 1;
        foodY = rand() % (HEIGHT - 2) + 1;

       
        for (int i = 0; i < snakeLength; i++) {
            if (snakeX[i] == foodX && snakeY[i] == foodY) {
                valid = false;
                break;
            }
        }

        
        if (foodX == 0 || foodX == WIDTH - 1 || foodY == 0 || foodY == HEIGHT - 1) {
            valid = false;
        }
    } while (!valid);

   
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos = { foodX, foodY };
    SetConsoleCursorPosition(hConsole, pos);
    SetConsoleTextAttribute(hConsole, 12); 
    printf("$");
}


int biteSelf() {
    for (int i = 1; i < snakeLength; i++) {
        if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
            return 1;
        }
    }
    return 0;
}


void cantCrossWall() {
    if (snakeX[0] <= 0 || snakeX[0] >= WIDTH - 1 || snakeY[0] <= 0 || snakeY[0] >= HEIGHT - 1) {
        gameOver = true;
    }
}


void speedUp() {
    if (speed > 50) {
        speed -= 30;
    }
    score += 2;
}


void speedDown() {
    if (speed < 350) {
        speed += 30;
    }
    if (score > 0) {
        score -= 2;
    }
    else {
        score = 0;
    }
}


void snakeMove() {
    while (!gameOver) {
        keyboardControl();

        
        HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
        COORD pos = { snakeX[snakeLength - 1], snakeY[snakeLength - 1] };
        SetConsoleCursorPosition(hConsole, pos);
        printf(" ");

        
        for (int i = snakeLength - 1; i > 0; i--) {
            snakeX[i] = snakeX[i - 1];
            snakeY[i] = snakeY[i - 1];
        }

        
        switch (direction) {
        case 1: 
            snakeY[0]--;
            break;
        case 2: 
            snakeX[0]++;
            break;
        case 3: 
            snakeY[0]++;
            break;
        case 4: 
            snakeX[0]--;
            break;
        }

        
        if (snakeX[0] == foodX && snakeY[0] == foodY) {
            snakeLength++;
            score += 10;
            createFood();
        }

        
        SetConsoleTextAttribute(hConsole, 14); 
        for (int i = 0; i < snakeLength; i++) {
            pos.X = snakeX[i];
            pos.Y = snakeY[i];
            SetConsoleCursorPosition(hConsole, pos);
            if (i == 0) {
                printf("@"); 
            }
            else {
                printf("*"); 
            }
        }

        
        cantCrossWall();
        if (biteSelf()) {
            gameOver = true;
        }

        scoreAndTips();
        Sleep(speed);
    }
    gameOverScreen();
}


void keyboardControl() {
    if (_kbhit()) {
        switch (_getch()) {
        case 72: 
            if (direction != 3) direction = 1;
            break;
        case 77: 
            if (direction != 4) direction = 2;
            break;
        case 80: 
            if (direction != 1) direction = 3;
            break;
        case 75: 
            if (direction != 2) direction = 4;
            break;
        case 27: 
            gameOver = true;
            break;
        case 59: 
            speedUp();
            break;
        case 60: 
            speedDown();
            break;
        }
    }
}


void gameOverScreen() {
    system("cls");
    printf("\n\n      游戏结束!\n\n");
    printf("      你的得分: %d\n", score);

    if (score > highScore) {
        printf("      创纪录啦！最高分被你刷新啦，真棒！！！\n");
        highScore = score;
        fileOut();
    }
    else {
        printf("      继续努力吧~你离最高分还差: %d\n", highScore - score);
    }

    printf("\n      1. 重新开始\n");
    printf("      2. 退出游戏\n\n");
    printf("      请选择(1-2): ");

    char choice = _getch();
    switch (choice) {
    case '1':
        welcomeToGame();
        break;
    case '2':
        exit(0);
    default:
        printf("\n      无效输入，请重新选择!");
        Sleep(1000);
        gameOverScreen();
    }
}


void explanation() {
    system("cls");
    printf("\n\n      游戏说明:\n\n");
    printf("      1. 使用方向键控制蛇的移动方向\n");
    printf("      2. 吃到食物($)可以增加蛇的长度和得分\n");
    printf("      3. 按F1加速，按F2减速\n");
    printf("      4. 按ESC键可以随时退出游戏\n");
    printf("      5. 撞到墙壁或自己的身体会导致游戏结束\n\n");
    printf("      按任意键返回...");
    _getch();
    welcomeToGame();
}